﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using Sripirom.ATS.Core.Configuration;
using log4net;
using log4net.Config;
using System.Globalization;
using System.ComponentModel;
using System.Text;
using Sripirom.ATS.Core.Helpers;

namespace Sripirom.ATS.Core.Logging
{
    public class Log4NetAdapter : ILogger
    {
        private  log4net.ILog _log;
       // private StackTrace _stackTrace = new StackTrace(true);
        //public Log4NetAdapter()
        //{
        //    if (_log == null)
        //    {
               
        //        XmlConfigurator.ConfigureAndWatch(
        //            new FileInfo(Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
        //                "log4net.config")));

                
        //    }

        //    //if (_log == null)
        //    //{
        //    //    FileInfo logConfig = new FileInfo(AppSettingsFactory.ConfigNames().LoggerName);
        //    //    XmlConfigurator.Configure(logConfig);
        //    //    _log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        //    //}

        //}
        public Log4NetAdapter(String name)
        {
            if (_log == null)
            {
                XmlConfigurator.ConfigureAndWatch(
                    new FileInfo(Path.Combine(AppDomain.CurrentDomain.BaseDirectory,
                        String.Format("{0}.config",name)))  );

                _log = log4net.LogManager.GetLogger(name);
                _log.Info(String.Format("Create Log from {0}.config", name));
            }

            //if (_log == null)
            //{
            //    FileInfo logConfig = new FileInfo(AppSettingsFactory.ConfigNames().LoggerName);
            //    XmlConfigurator.Configure(logConfig);
            //    _log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
            //}
            
        }

     
        private void SettingProperties(StackTrace stackTrace)
        {
            //if (System.ServiceModel.OperationContext.Current == null || System.ServiceModel.OperationContext.Current.RequestContext.RequestMessage == null)
            //{
            //    _log = LogManager.GetLogger(AppSettingsFactory.ConfigNames().LoggerName);
            //}else
            
            //{
            //   // System.ServiceModel.OperationContext.Current
            //    String serviceName = System.ServiceModel.OperationContext.Current.RequestContext.RequestMessage.Headers.To.AbsolutePath;
            //    //LogManager.GetLogger(AppSettingsFactory.ConfigNames().LoggerName).Info(serviceName);
            //    serviceName = serviceName.Substring(serviceName.LastIndexOf('/') + 1);
            //    //LogManager.GetLogger(AppSettingsFactory.ConfigNames().LoggerName).Info(serviceName);
            //    serviceName = serviceName.Replace(".svc", "");
            //    //LogManager.GetLogger(AppSettingsFactory.ConfigNames().LoggerName).Info(serviceName);
            //    _log = LogManager.GetLogger(serviceName.ToLower());
            //}
               

            StackFrame frame = stackTrace.GetFrame(1);
            MethodBase methodBase = frame.GetMethod();

            if (methodBase.DeclaringType != null)
                log4net.LogicalThreadContext.Properties["caller"] = methodBase.DeclaringType.ToString() + "." + methodBase.Name + ", " + frame.GetFileLineNumber();

        }
        public void Debug(string message,object messageRequest)
        {
#if DEBUG
            if (!String.IsNullOrWhiteSpace(message))
            {
                SettingProperties(new StackTrace(true));
                var messageToTrace = string.Format(CultureInfo.InvariantCulture, message, SerializationHelper.SerializeToString(messageRequest));

                _log.Debug(messageToTrace);

            }
#endif
        }
        public void Debug(string message, params object[] args)
        {
#if DEBUG
            if (!String.IsNullOrWhiteSpace(message))
            {
                SettingProperties(new StackTrace(true));
                var messageToTrace = StringFormat(message, args);

                _log.Debug(messageToTrace);

            }
#endif
        }

        public void Debug(string message, Exception exception, params object[] args)
        {
#if DEBUG
            if (!String.IsNullOrWhiteSpace(message))
            {
                SettingProperties(new StackTrace(true));
                var messageToTrace = StringFormat(message, args);

                _log.Debug(messageToTrace, exception);

            }
#endif
        }

        public void Debug(object item)
        {
#if DEBUG
            if (item != null)
            {
                SettingProperties(new StackTrace(true));

                if (item == null)
                {
                    _log.Debug(String.Format("\n{0}:{1}", item.GetType().ToString(), "NULL"));
                }
                else
                {
                    if (!IsBulitin(item))
                        _log.Debug(WriteProperties(0, item));
                    else
                    {
                        _log.Debug(String.Format("{0}", item));
                    }
                }


            }
#endif
        }
        private String WriteProperties(int index, object item) 
        {
            index++;
            StringBuilder propLog = new StringBuilder();
            propLog.AppendLine(item.GetType().ToString());

            if (item == null)
                return propLog.ToString();
            propLog.AppendLine(getTab(index-1)+"{");
            
            foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(item))
            {
                string name = descriptor.Name;
                object value = descriptor.GetValue(item);

                if (value!=null && !IsBulitin(value))
                {
                   propLog.AppendLine(String.Format("{0}{1}={2}",getTab(index), name, (value == null) ? "NULL" : WriteProperties(index, value)));
                }
                else
                {
                    propLog.AppendLine(String.Format("{0}{1}={2}",getTab(index), name, (value == null) ? "NULL" : value));
                }

            }
            propLog.Append(getTab(index-1) + "}");
            return propLog.ToString();
        }
        private String getTab(Int32 index) {
            String tabs = "";
            for(int i=0; i<index;i++){
                tabs += " \t";
            }
            return tabs;
        }
        private bool IsBulitin(object o)
        {
            var type = o.GetType();
            return (type.IsPrimitive && type != typeof(IntPtr) && type != typeof(UIntPtr))
                  || type == typeof(string)
                  || type == typeof(object)
                  || type == typeof(Decimal)
                  || type == typeof(DateTime)
                  || type == typeof(Int16)
                  || type == typeof(Int32)
                  || type == typeof(Int64);
        }

        public void Fatal(string message, params object[] args)
        {
            if (!String.IsNullOrWhiteSpace(message))
            {
                SettingProperties(new StackTrace(true));
                var messageToTrace = StringFormat(message, args);

                _log.Fatal(messageToTrace);

            }
        }

        public void Fatal(string message, Exception exception, params object[] args)
        {
            if (!String.IsNullOrWhiteSpace(message))
            {
                SettingProperties(new StackTrace(true));
                var messageToTrace = StringFormat(message, args);

                _log.Fatal(messageToTrace, exception);

            }
        }

        public void LogInfo(string message, params object[] args)
        {


            if (!String.IsNullOrWhiteSpace(message))
            {
                SettingProperties(new StackTrace(true));
                var messageToTrace = StringFormat(message, args);

                _log.Info(messageToTrace);
             
            }
        }

        public void LogWarning(string message, params object[] args)
        {
            if (!String.IsNullOrWhiteSpace(message))
            {
                SettingProperties(new StackTrace(true));
                var messageToTrace = StringFormat(message, args);

                _log.Warn(messageToTrace);

            }
        }

        public void LogError(string message, params object[] args)
        {
            if (!String.IsNullOrWhiteSpace(message))
            {
                SettingProperties(new StackTrace(true));
                var messageToTrace = StringFormat(message, args);

                _log.Error(messageToTrace);

            }
        }

        public void LogError(string message, Exception exception, params object[] args)
        {
            if (!String.IsNullOrWhiteSpace(message))
            {
                SettingProperties(new StackTrace(true));
                var messageToTrace = StringFormat( message, args);

                _log.Error(messageToTrace, exception);

            }
        }



        private string StringFormat(string message, params object[] args) 
        {
            return (args.Length == 0)? message : string.Format(CultureInfo.InvariantCulture, message, args);
        }

    }

}
